package com.iqiyi.pps.epg.web.timer;

import com.alibaba.fastjson.JSONObject;
import com.iqiyi.pps.epg.core.dao.carousel.AutoCarouselEpisodeRuleDao;
import com.iqiyi.pps.epg.core.dao.program.ProgramDataDao;
import com.iqiyi.pps.epg.core.service.notifymail.NotifyMailService;
import com.iqiyi.pps.epg.core.utils.ApiHttpRequestUtil;
import com.iqiyi.pps.epg.core.utils.SendMailUtils;
import com.iqiyi.pps.epg.core.utils.mail.MailConstant;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Created by lemuel on 2017/4/19.
 */

@Transactional
public class DailyCheckTrigger {
    private static Logger logger = LoggerFactory.getLogger(DailyCheckTrigger.class);

    public static final String HTML_PRE = "<html><head><meta http-equiv=\"content-type\" content=\"text/html;charset=utf8\"></head>";
    public static final String BODY_PRE = "<body>";
    public static final String BODY_END = "</body>";
    public static final String STYLE_PRE = "<style>";
    public static final String STYLE_END = "</style>";
    public static final String HTML_END = "</html>";
    public static final String TABLE_PRE = "<table border='1' table border='1' cellspacing='0' cellpadding='0' class='table'>";
    public static final String TABLE_END = "</table>";
    public static final String TR_PRE = "<tr>";
    public static final String TR_END = "</tr>";
    public static final String BODY_STYLE = ".table thead, .table tr {border-top-width: 1px; border-top-style: solid; border-top-color: rgb(173, 216, 230);} .table {border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(173, 216, 230);} .table td, .table th {padding: 5px 10px; font-size: 12px; font-family: Verdana; color: rgb(0, 0, 0);} .table tr:nth-child(even) {background: rgb(173, 216, 230)} .table tr:nth-child(odd) {background: #FFF}";

    public static final String TD_PRE = "<td class=\"tdClass\">";
    public static final String TD_PRE_LEFT = "<td class=\"tdClassLeft\">";
    public static final String TD_PRE_RED = "<td style='background:red;color:white;'>";
    public static final String TD_END = "</td>";

    public static final String TH_PRE = "<th>";
    public static final String TH_END = "</th>";

    public static final String TH_ROWSPAN_PRE = "<th colspan=\"%d\">";
    public static final String TH_COLSPAN_PRE = "<th rowspan=\"%d\">";

    public static final String SPAN_RED = "<span style=\"color:red;\">";
    public static final String SPAN_GREEN = "<span style=\"color:green;\">";
    public static final String SPAN_END = "</span>";
    public static final String BR = "<br>";

    public static final String DAILYCHECK_TITLE = "EPG直播流 - 每日检查";
    public static final String DAILYCHECK_CUTTER_TITLE = "CUTTER服务器";
    public static final String DAILYCHECK_CUTTER_STRING = "FLV: 总计 – %d, 剩余 – %d  |  TS: 总计 – %d, 剩余 – %d";
    public static final String DAILYCHECK_CUTTER_FLV_URL = "http://cutteradmin.qiyi.domain:7777/channelusage?user=ppslive";
    public static final String DAILYCHECK_CUTTER_TS_URL = "http://cutteradmin.qiyi.domain:7777/m3u8_tsusage?user=ppslive";

    public static final String DAILYCHECK_LINSHI_TITLE = "临时直播检查";
    public static final String DAILYCHECK_LINSHI_HINT = "今日到明日上午十点节目库中的临时直播";
    public static final String DAILYCHECK_LINSHI_COLUMNS_0 = "临时直播频道";
    public static final String DAILYCHECK_LINSHI_COLUMNS_1 = "节目等级";
    public static final String DAILYCHECK_LINSHI_COLUMNS_2 = "开始时间";
    public static final String DAILYCHECK_LINSHI_COLUMNS_3 = "结束时间";
    public static final String DAILYCHECK_LINSHI_SQL = "SELECT c.name, f.descr, l.start_play_time, l.stop_play_time FROM live_episode l JOIN channel_base c ON l.father_id = c.id JOIN channel_config f on f.`key` = l.episode_grade AND f.type = 'EpisodeGradeType' AND c.live_type = 2 AND c.is_enable = 1 AND c.formal = 1 AND l.start_play_time >= CONCAT(CURDATE(), ' 10:00:00') AND l.start_play_time <= CONCAT(ADDDATE(CURDATE(), 1), ' 10:00:00') ORDER BY l.start_play_time";

    public static final String DAILYCHECK_LUNBO_TITLE = "轮播台信息";
    public static final String DAILYCHECK_LUNBO_SQL = "SELECT cba.`name`,IF (cba.is_automation = 1,'是','否'),IF (cba.is_enable = 1,'启用','未启用'),IF (isnull(cbc.day0),0,cbc.day0) AS day0,IF (isnull(cbc.day1),0,cbc.day1) AS day1,IF (isnull(cbc.day2),0,cbc.day2) AS day2,IF (isnull(cbc.day3),0,cbc.day3) AS day3,IF (isnull(cbc.day4),0,cbc.day4) AS day4,IF (isnull(cbc.day5),0,cbc.day5) AS day5,IF (isnull(cbc.day6),0,cbc.day6) AS day6,IF (isnull(cbc.day7),0,cbc.day7) AS day7,IF (isnull(cbc.day8),0,cbc.day8) AS day8,IF (isnull(cbc.day9),0,cbc.day9) AS day9,IF (isnull(cbc.exec_time),'',cbc.exec_time) FROM (SELECT cb.id,cb.`name`,cb.is_enable,cb.is_automation FROM channel_base cb WHERE cb.is_enable != - 1 AND cb.live_type = 3 AND cb.id != 100260) cba LEFT JOIN (SELECT c.id,concat(convert(sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 0) AND l.start_play_time < ADDDATE(CURDATE(), 1) THEN 1 ELSE 0 END),UNSIGNED),' / ',round(SUM(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 0) AND l.start_play_time < ADDDATE(CURDATE(), 1) THEN TIMESTAMPDIFF(SECOND,l.start_play_time,l.stop_play_time) ELSE 0 END) / 3600,1)) 'day0',concat(convert(sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 1) AND l.start_play_time < ADDDATE(CURDATE(), 2) THEN 1 ELSE 0 END),UNSIGNED),' / ',round(sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 1) AND l.start_play_time < ADDDATE(CURDATE(), 2) THEN TIMESTAMPDIFF(SECOND,l.start_play_time,l.stop_play_time) ELSE 0 END) / 3600,1)) 'day1',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 2) AND l.start_play_time < ADDDATE(CURDATE(), 3) THEN 1 ELSE 0 END) 'day2',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 3) AND l.start_play_time < ADDDATE(CURDATE(), 4) THEN 1 ELSE 0 END) 'day3',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 4) AND l.start_play_time < ADDDATE(CURDATE(), 5) THEN 1 ELSE 0 END) 'day4',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 5) AND l.start_play_time < ADDDATE(CURDATE(), 6) THEN 1 ELSE 0 END) 'day5',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 6) AND l.start_play_time < ADDDATE(CURDATE(), 7) THEN 1 ELSE 0 END) 'day6',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 7) AND l.start_play_time < ADDDATE(CURDATE(), 8) THEN 1 ELSE 0 END) 'day7',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 8) AND l.start_play_time < ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END) 'day8',sum(CASE WHEN l.start_play_time >= ADDDATE(CURDATE(), 9) AND l.start_play_time < ADDDATE(CURDATE(), 10) THEN 1 ELSE 0 END) 'day9',(CASE WHEN c.is_automation = 1 THEN a.execute_time ELSE ''END) 'exec_time'FROM live_episode l JOIN channel_base c ON c.id = l.father_id LEFT OUTER JOIN (SELECT * FROM (SELECT id,father_id,execute_time FROM autocarousel_episode_rule ORDER BY execute_time DESC) aer GROUP BY aer.father_id) a ON a.father_id = l.father_id WHERE c.is_enable != - 1 AND c.live_type = 3 AND c.id != 100260 AND l.is_delete = 0 GROUP BY c.id) cbc ON cba.id = cbc.id ORDER BY cba.is_enable DESC,cba.is_automation DESC";

    public static final String DAILYCHECK_AUTORULE_TITLE = "自动规则执行情况";
    public static final String DAILYCHECK_AUTORULE_SQL = "SELECT count(0), sum(IF(repeated_status = 1, 1, 0)), sum(CASE WHEN repeated_status = 1 AND extend_time >= ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ), sum(CASE WHEN repeated_status = 1 AND extend_time < ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ), sum(IF(followed_status = 1, 1, 0)), sum(CASE WHEN followed_status = 1 AND end_time < ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ), sum(CASE WHEN followed_status = 1 AND end_time >= ADDDATE(CURDATE(), 9) AND extend_time >= ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ) follow_succ, sum(CASE WHEN followed_status = 1 AND end_time >= ADDDATE(CURDATE(), 9) AND extend_time < ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ) follow_fail, sum(CASE WHEN repeated_status = 2 AND followed_status = 2 THEN 1 ELSE 0 END ) AS normal, sum(CASE WHEN repeated_status = 2 AND followed_status = 2 AND end_time < ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ) AS normal_over, sum(CASE WHEN repeated_status = 2 AND followed_status = 2 AND end_time >= ADDDATE(CURDATE(), 9) AND extend_time >= ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ) AS normal_succ, sum(CASE WHEN repeated_status = 2 AND followed_status = 2 AND end_time >= ADDDATE(CURDATE(), 9) AND extend_time < ADDDATE(CURDATE(), 9) THEN 1 ELSE 0 END ) AS normal_fail FROM carousel_episode_rule a JOIN channel_base b ON father_id = b.id WHERE a.`status` = 1 AND b.is_enable >= 0";

    public static final String DAILYCHECK_PROGRAMSYNC_TITLE = "当前所有节目未同步奇谱数量";
    public static final String DAILYCHECK_PROGRAMSYNC_SQL = "select count(0) '未完成同步的节目数量' from live_episode where is_sync = 0 and start_play_time < ADDTIME(now(),'24:0:0') and qipu_id > 0 ORDER BY start_play_time";

    public static final String DAILYCHECK_OVERPROGRAM_TITLE = "大于3000个节目的频道";
    public static final String DAILYCHECK_OVERPROGRAM_SQL = "SELECT channel.qipu_id as '奇谱ID', channel.`name` AS '频道名称', CASE WHEN channel.live_type = '3' THEN '轮播台'WHEN channel.live_type = '2' THEN '临时直播'WHEN channel.live_type = '1' THEN '常规直播'END AS '频道类型', count(0) AS 'total'FROM live_episode JOIN channel_base channel ON channel.id = father_id WHERE channel.is_enable != - 1 AND is_delete = 0 AND live_episode.qipu_id > 0 AND live_episode.is_sync = 1 GROUP BY father_id HAVING total > 3000 ORDER BY total DESC";

    public static final String DAILYCHECK_DAXIAOXIE_TITLE = "频道大小写分类自动下线异常";
    public static final String DAILYCHECK_DAXIAOXIE_SQL = "SELECT DISTINCT(channel.id), channel.name FROM live_episode AS program, channel_base channel, channel_tag cnlTag WHERE program.father_id = channel.id AND channel.is_enable != - 1 AND channel.live_type = 2 AND program.is_delete = 0 AND program.stop_play_time > ADDDATE(now(),-5) AND program.stop_play_time < now() AND cnlTag.father_id = channel.id AND cnlTag.tag2 != 200978719 and channel.id not in (SELECT program1.father_id from live_episode AS program1 join channel_base as channel1 on program1.father_id = channel1.id where ((program1.start_play_time <=now() and program1.stop_play_time >= now() ) or (program1.start_play_time >=now() and program1.start_play_time < ADDTIME(now(),'2:0:0') ) ) and channel1.live_type = 2)";

    public static final String DAILYCHECK_BROADCAST_TITLE = "节目播控同步奇谱情况异常检查";
    public static final String DAILYCHECK_BROADCAST_SQL = "SELECT program.id, program.program_name FROM live_episode program LEFT JOIN program_platform_control ppc ON program.id = ppc.program_id LEFT JOIN platform_control pc ON program.father_id = pc.father_id WHERE program.start_play_time >= CONCAT(CURDATE(), ' 00:00:00') AND program.start_play_time < concat(ADDDATE(CURDATE(), 2), ' 00:00:00') AND program.qipu_id > 0 AND program.is_delete = 0 AND ppc.id IS NULL AND pc.id IS NOT NULL GROUP BY program.id ORDER BY program.start_play_time";

    @Autowired
    ProgramDataDao programDataDao;

    @Autowired
    AutoCarouselEpisodeRuleDao autoCarouselEpisodeRuleDao;

    @Autowired
    private NotifyMailService notifyMailService;

    public void task() {
        StringBuffer content = new StringBuffer();

        content.append(HTML_PRE);
        content.append(STYLE_PRE);
        content.append(BODY_STYLE);
        content.append(STYLE_END);
        content.append(BODY_PRE);

        // 临时直播节目
        content.append("<p>" + DAILYCHECK_TITLE + "</p>");
        content.append(TABLE_PRE);
        content.append(TR_PRE);
        content.append("<th>");
        content.append(DAILYCHECK_CUTTER_TITLE);
        content.append("</th>");
        content.append("<td colspan='4'>");
        content.append(getCutterInfo());
        content.append(TD_END);
        content.append(TR_END);
        content.append(getLinshiInfo());
        content.append(TABLE_END);

        content.append("<p>" + DAILYCHECK_LUNBO_TITLE + "</p>");
        content.append(getLunboInfo());

        content.append("<p>" + DAILYCHECK_AUTORULE_TITLE + "</p>");
        content.append(getAutoruleInfo());

        content.append("<p>" + DAILYCHECK_PROGRAMSYNC_TITLE + "</p>");
        content.append(getProgramsyncInfo());

        content.append("<p>" + DAILYCHECK_OVERPROGRAM_TITLE + "</p>");
        content.append(getOverProgramInfo());

        content.append("<p>" + DAILYCHECK_DAXIAOXIE_TITLE + "</p>");
        content.append(getDaxiaoxieInfo());

        content.append("<p>" + DAILYCHECK_BROADCAST_TITLE + "</p>");
        content.append(getBroadcastInfo());

        content.append(BODY_END);
        content.append(HTML_END);

//        System.out.println(content.toString());
        sendMail(content.toString());
    }

    private void sendMail(String content) {
        boolean flag = SendMailUtils.sendMail("EPG直播流 - 每日检查", notifyMailService.getTos(0,0, MailConstant.TOS_TYPE_DAILYCHECK_MAIL_TYPE), content);
    }

    private String getCutterInfo() {
        String retFlv = ApiHttpRequestUtil.doGet(DAILYCHECK_CUTTER_FLV_URL, null, null);
        String retTs = ApiHttpRequestUtil.doGet(DAILYCHECK_CUTTER_TS_URL, null, null);

        boolean result = false;
        String resultStr = "获取信息失败";

        try {
            if(StringUtils.isNotEmpty(retFlv) && StringUtils.isNotEmpty(retTs)) {
                JSONObject flvInfo = JSONObject.parseObject(retFlv);
                JSONObject tsInfo = JSONObject.parseObject(retTs);

                if(null != flvInfo && null != tsInfo &&
                        flvInfo.getIntValue("status") == 1 && tsInfo.getIntValue("status") == 1) {
                    resultStr = String.format(DAILYCHECK_CUTTER_STRING,
                            flvInfo.getJSONObject("data").getIntValue("capacity"),
                            flvInfo.getJSONObject("data").getIntValue("remain"),
                            tsInfo.getJSONObject("data").getIntValue("capacity"),
                            tsInfo.getJSONObject("data").getIntValue("remain"));
                }
            }
        } catch (Exception e) {
            logger.info("[getCutterInfo] exception = " + e);
        }

        return resultStr;

    }

    private String getLinshiInfo() {
        List result = programDataDao.getSession().createSQLQuery(DAILYCHECK_LINSHI_SQL).list();
        StringBuffer sb = new StringBuffer();

        int len = result.size() + 2;

        sb.append(TR_PRE);
        sb.append(String.format(TH_COLSPAN_PRE, len));
        sb.append(DAILYCHECK_LINSHI_TITLE);
        sb.append(TH_END);
        sb.append(String.format(TH_ROWSPAN_PRE, 4));
        sb.append(DAILYCHECK_LINSHI_HINT);
        sb.append(TH_END);
        sb.append(TR_END);

        sb.append(makeElement("tr",
                makeTd(DAILYCHECK_LINSHI_COLUMNS_0),
                makeTd(DAILYCHECK_LINSHI_COLUMNS_1),
                makeTd(DAILYCHECK_LINSHI_COLUMNS_2),
                makeTd(DAILYCHECK_LINSHI_COLUMNS_3)));

        for (Object single : result) {
            Object[] obj = (Object[]) single;

            sb.append(makeElement("tr",
                    makeTd(obj[0].toString()),
                    makeTd(obj[1].toString()),
                    makeTd(obj[2].toString()),
                    makeTd(obj[3].toString())));
        }
        return sb.toString();
    }

    private String getLunboInfo() {
        List result = programDataDao.getSession().createSQLQuery(DAILYCHECK_LUNBO_SQL).list();
        StringBuffer sb = new StringBuffer();

        sb.append(TABLE_PRE);
        sb.append(makeElement("tr",
                makeTd("轮播台频道"),
                makeTd("自动化"),
                makeTd("频道状态"),
                getDateTdRange(10),
                makeTd("最后自动化规则执行时间")));

        for(Object single : result) {
            Object[] obj = (Object[]) single;

            boolean isWarning = true;
            if(obj[2].toString().equals("未启用")) {
                isWarning = false;
            }

            sb.append(makeElement("tr",
                    makeTd(obj[0].toString()),
                    makeTd(obj[1].toString()),
                    makeTd(obj[2].toString()),
                    makeTd(obj[3].toString(), isWarning),
                    makeTd(obj[4].toString(), isWarning),
                    makeTd(obj[5].toString(), isWarning),
                    makeTd(obj[6].toString(), isWarning),
                    makeTd(obj[7].toString(), isWarning),
                    makeTd(obj[8].toString(), isWarning),
                    makeTd(obj[9].toString(), isWarning),
                    makeTd(obj[10].toString(), isWarning),
                    makeTd(obj[11].toString(), isWarning),
                    makeTd(obj[12].toString(), isWarning),
                    makeTd(obj[13].toString())
            ));
        }

        sb.append(TABLE_END);

        return sb.toString();
    }

    private String getAutoruleInfo() {
        List result = autoCarouselEpisodeRuleDao.getSession().createSQLQuery(DAILYCHECK_AUTORULE_SQL).list();
        StringBuffer sb = new StringBuffer();

        sb.append(TABLE_PRE);

        sb.append(makeElement("tr",
                makeTd("total"),
                makeTd("repeat"),
                makeTd("repeat_succ"),
                makeTd("repeat_fail"),
                makeTd("follow"),
                makeTd("follow_over"),
                makeTd("follow_succ"),
                makeTd("follow_fail"),
                makeTd("normal"),
                makeTd("normal_over"),
                makeTd("normal_succ"),
                makeTd("normal_fail")
        ));

        for(Object single : result) {
            Object[] obj = (Object[]) single;

            if("0".equals(obj[0].toString())) {
                break;
            }

            sb.append(makeElement("tr",
                    makeTd(obj[0].toString()),
                    makeTd(obj[1].toString()),
                    makeTd(obj[2].toString()),
                    makeTd(obj[3].toString()),
                    makeTd(obj[4].toString()),
                    makeTd(obj[5].toString()),
                    makeTd(obj[6].toString()),
                    makeTd(obj[7].toString()),
                    makeTd(obj[8].toString()),
                    makeTd(obj[9].toString()),
                    makeTd(obj[10].toString()),
                    makeTd(obj[11].toString())
            ));
        }

        sb.append(TABLE_END);
        return sb.toString();
    }

    private String getProgramsyncInfo() {
        List result = programDataDao.getSession().createSQLQuery(DAILYCHECK_PROGRAMSYNC_SQL).list();
        StringBuffer sb = new StringBuffer();

        sb.append(TABLE_PRE);

        sb.append(makeElement("tr",
                makeElement("th", "未完成同步的节目数量")));

        for(Object single : result) {
            sb.append(makeElement("tr", makeTd(single.toString())));
        }

        sb.append(TABLE_END);

        return sb.toString();
    }

    private String getOverProgramInfo() {
        List result = programDataDao.getSession().createSQLQuery(DAILYCHECK_OVERPROGRAM_SQL).list();

        StringBuffer sb = new StringBuffer();

        if(result.size() < 1) {
            sb.append("无");
        }else{
            sb.append(TABLE_PRE);
            sb.append(makeElement("tr",
                    makeTd("奇谱ID"),
                    makeTd("频道名称"),
                    makeTd("频道类型"),
                    makeTd("total")
            ));

            for(Object single : result) {
                Object[] obj = (Object[]) single;
                sb.append(makeElement("tr",
                        makeTd(obj[0].toString()),
                        makeTd(obj[1].toString()),
                        makeTd(obj[2].toString()),
                        makeTd(obj[3].toString())
                ));
            }
            sb.append(TABLE_END);
        }

        return sb.toString();
    }

    private String getDaxiaoxieInfo() {
        List result = programDataDao.getSession().createSQLQuery(DAILYCHECK_DAXIAOXIE_SQL).list();

        StringBuffer sb = new StringBuffer();

        if(result.size() < 1) {
            sb.append("无");
        }else{
            sb.append(TABLE_PRE);
            sb.append(makeElement("tr",
                    makeTd("id"),
                    makeTd("name")
            ));

            for(Object single : result) {
                Object[] obj = (Object[]) single;
                sb.append(makeElement("tr",
                        makeTd(obj[0].toString()),
                        makeTd(obj[1].toString())
                ));
            }
            sb.append(TABLE_END);
        }

        return sb.toString();
    }

    private String getBroadcastInfo() {
        List result = programDataDao.getSession().createSQLQuery(DAILYCHECK_BROADCAST_SQL).list();

        StringBuffer sb = new StringBuffer();

        if(result.size() < 1) {
            sb.append("无");
        }else{
            sb.append(TABLE_PRE);
            sb.append(makeElement("tr",
                    makeTd("id"),
                    makeTd("节目名称")
            ));

            for(Object single : result) {
                Object[] obj = (Object[]) single;
                sb.append(makeElement("tr",
                        makeTd(obj[0].toString()),
                        makeTd(obj[1].toString())
                ));
            }
            sb.append(TABLE_END);
        }

        return sb.toString();
    }

    private static String makeTd(String content) {
        return TD_PRE + content + TD_END;
    }

    private static String makeTd(String content, boolean isWarning) {
        try {
            if(!isWarning) {
                return makeTd(content);
            }

            int val = Integer.valueOf(content.replace(" ", "").split("/")[0]);
            if (val <= 10) {
                return TD_PRE_RED + content + TD_END;
            }else{
                return TD_PRE + content + TD_END;
            }
        } catch (NumberFormatException e) {
            logger.info("[makeTd] exception = " , e);
        }
        return TD_PRE + content + TD_END;
    }

    private static String makeElement(String tag, String content) {
        return "<" + tag + ">" + content + "</" + tag + ">";
    }

    private static String makeElement(String tag, String... contents) {
        StringBuffer sb = new StringBuffer();
        sb.append("<" + tag + ">");
        for (String c : contents) {
            sb.append(c);
        }
        sb.append("</" + tag + ">");

        return sb.toString();
    }

    private static String getCurrentDay() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Long realMill = System.currentTimeMillis();
        Date now = new Date(realMill);
        String today = sdf.format(now);
        return today;
    }

    private static String getDate(int offset) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Long realMill = System.currentTimeMillis();
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTimeInMillis(realMill);
        rightNow.add(Calendar.DATE, offset);
        String day = sdf.format(rightNow.getTime());
        return day;
    }

    private static String getDateTdRange(int offset) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < offset; i++) {
            sb.append(makeTd(getDate(i)));
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        System.out.println(getCurrentDay());
        System.out.println(getDate(-1));
    }

}
